import {
  Button,
  ConstraintType,
  CSDashLine,
  CSPoint,
  EventsRes,
  ICurve,
  SceneGraph,
} from '@amcax/base';
import { ctx2, previewer } from '@app-cad/module';
// Vector2tuple
import { wsApi } from '@app-cad/server';
import { Object3D, Vector2tuple, Vector3 } from 'three-legacy';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '../../../events/SketchEventCenter';
import CmdBase, { PickType, ReturnDataInfo } from '../../CmdBase';
import { dimRender } from '../cmd-render-pick/render';
import { State } from './types';
import { axis, dashOptions, lineWidthOptions } from '@app-base/common/utils';
import { getCurveIdsByGroupId } from '../cmd-render-pick/tools';
import { GroupsType } from '../cmd-render-pick/type';

export class CmdDrag extends CmdBase {
  public selectedCurve: ICurve & { groups?: GroupsType[] };
  // 鼠标是否按下
  private mouseDown: boolean = false;
  // 操作类型
  private actionType: State = State.NONE;
  // 临时点
  private tempPoint: Vector3;
  // 当前拖动点的样条曲线信息，做预览用
  private nowsplineData;
  // 可执行
  private isExecute: boolean = true;
  static instance: CmdDrag;
  // 结束点
  private endPoint: Vector2tuple = null;
  constructor() {
    super();
    const element = document.querySelector('html');
    element.addEventListener('mouseup', () =>
      this.onMouseUp({ button: { onLeft: true } }),
    );
  }
  static removeInstance() {
    if (this.instance) {
      this.instance = null;
    }
  }
  static getInstance(): CmdDrag {
    if (!this.instance) {
      this.instance = new CmdDrag();
    }
    return this.instance;
  }
  setPickedCurve(pickedCurve: ICurve) {
    if (pickedCurve && !axis.includes(pickedCurve?.id)) {
      this.pickedCurve = pickedCurve as ICurve & { relative: string[] };
    } else {
      this.pickedCurve = null;
    }
  }
  reset() {
    this.mouseDown = false;
    this.actionType = State.NONE;
    this.assistPoints = [];
    this.tempPoint = null;
    this.isExecute = true;
    this.nowsplineData = null;
    if (this._constraint) {
      this._constraint.geoRelation = null;
    }
    this.selectedCurve = null;
    this.unPickedIds = [];
  }
  registerEvents() {}
  unregisterEvents() {}
  releaseObjects() {
    this.assisGroup.clear();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  }
  // 按下移动
  async onMouseDownMove(e: EventsRes) {
    this.setMouseWV(e);

    if (this.actionType === State.NONE && this.pickedCurve?.id) {
      dimRender().hidden(); // 隐藏尺寸
      this.tempPoint = this.mouseWV;
      if (this.pickedCurve?.type === 'Bspline') {
        this.actionType = State.BSPLINE;
      } else if (this.pickedCurve?.type === 'Point') {
        this.actionType = State.POINT;
      } else {
        this.actionType = State.LINE;
      }
      this.selectedCurve = this.pickedCurve;
      // 关闭属性弹框
      sketchEventCenter().emit(SKETCH_CENTEREVENTS.MOUSEDOWNMOVE);
      // 设置点位根据鼠标位置
      // this.setUnPickedIds();
      const groupids = this.selectedCurve.groups.map((item) => item.groupid);
      const ids = getCurveIdsByGroupId(groupids, null, ['Point', 'Line']);
      this.unPickedIds = ids;
    }
    // 点击的是线
    if (this.actionType !== State.NONE) {
      this.preview();
    }
  }
  // 鼠标移动
  onMouseMove = (e: EventsRes) => {
    if (this.mouseDown) {
      this.onMouseDownMove(e);
      return null;
    }
  };
  // 鼠标按下
  onMouseDown = ({ button }: { button?: Button }) => {
    if (button.onLeft) {
      this.mouseDown = true;
    }
  };
  onMouseUp = ({ button: { onLeft } }: { button?: { onLeft?: boolean } }) => {
    this.mouseDown = false;
    if (onLeft && this.actionType !== State.NONE) {
      this.finishCraft();
      this.resetDraw();
    }
  };
  // 取消绘制
  resetDraw() {
    this.reset();
    this.releaseObjects();
  }
  async preview() {
    if (!this.isExecute) {
      return;
    }
    this.picker.clickNull();
    const curveId = this.selectedCurve.id;
    this.executeTransaction(curveId);
  }
  // 获取样条曲线整体移动偏移顶点数据
  getBsplinePoint() {
    const x = this.mouseWV.x - this.tempPoint.x;
    const y = this.mouseWV.y - this.tempPoint.y;
    const vertices: Vector2tuple[] = this.selectedCurve.vertices.map((item) => [
      item[0] + x,
      item[1] + y,
    ]);
    const inputPoints = this.selectedCurve.otherInfo.bspline_point.map(
      (item) => [item[0] + x, item[1] + y],
    );
    return { vertices, inputPoints };
  }
  // 拖拽预览
  async executeTransaction(curveId: string) {
    this.isExecute = false;
    try {
      const start: Vector2tuple = [this.tempPoint.x, this.tempPoint.y];
      const end: Vector2tuple = [this.mouseWV.x, this.mouseWV.y];
      const tempData = await wsApi.moveSketcher(
        this.sketchId,
        curveId,
        end,
        start,
        true,
      );
      this.isExecute = true;
      this.endPoint = end;
      this.drawCurves(tempData.curves);
    } catch (error) {
      this.isExecute = true;
      previewer.clear();
    }
  }
  getPointIndex() {
    const pointIndex = this.nowsplineData.relative.findIndex(
      (ele) => ele === this.selectedCurve?.id,
    );

    return pointIndex;
  }
  getBsplineParams() {
    const BslineParmas = this.nowsplineData.otherInfo;

    BslineParmas.bspline_point[this.getPointIndex()] = [
      this.mouseWV.x,
      this.mouseWV.y,
    ];
    return { inputPoints: BslineParmas.bspline_point };
  }
  async finishCraft(): Promise<void> {
    try {
      const pickType = this.pickType;
      const { curveId, srcCurveId, targetId } = this.getPrams();
      const start: Vector2tuple = [this.tempPoint.x, this.tempPoint.y];
      const modifyData: ReturnDataInfo = await wsApi.moveSketcher(
        this.sketchId,
        this.selectedCurve?.id,
        this.endPoint,
        start,
        false,
      );
      // 添加约束
      this.addConstraint(targetId, srcCurveId, pickType);
      // 局部渲染
      if (!modifyData.changed.includes(curveId)) {
        modifyData.changed.push(curveId);
      }
      await this.render(modifyData);
      previewer.clear();
    } catch (error) {
      console.error(error);
      previewer.clear();
      dimRender().show();
    }
  }
  getPrams() {
    // 目标
    const targetId = this.selectedCurve;
    const srcCurveId = this.pickSnapInfo;
    // 如果是单独的点
    const curveId = this.selectedCurve?.id;
    return {
      curveId,
      targetId,
      srcCurveId,
    };
  }
  setUnPickedIds(id: string) {
    if (this.unPickedIds.length > 0) {
      return;
    }
    const curves = dimRender().getSketMap();
    const ellipse = curves.get(id);
    this.unPickedIds = [...ellipse['real_relative'].map((item) => item.id), id];
  }
  // 绘制曲线 - 预览
  private drawCurves(curves: Array<ICurve>) {
    const previewScene = new Object3D();
    for (let i = 0; i < curves.length; i++) {
      this.drawCurvePreview(curves[i], previewScene);
      if (curves[i].type === 'Ellipse') {
        this.setUnPickedIds(curves[i].id);
      }
    }
    previewer.preview([previewScene]);
  }
  // 绘制曲线 - 预览
  drawCurvePreview(curve: ICurve, previewScene: Object3D) {
    if (
      (curve.type === 'Point' && this.actionType !== State.POINT) ||
      curve?.id.includes(axis[1]) ||
      curve?.id.includes(axis[0])
    ) {
      return;
    }

    const positions = [];
    // 画曲线
    for (let i = 0; i < curve.vertices.length; i++) {
      const pos = this.sketchFrame.toWorld(
        new Vector3(curve.vertices[i][0], curve.vertices[i][1], 0),
      );
      positions.push(new Vector3(pos.x, pos.y, pos.z));
    }
    const center = curve.params?.['center'] || null;
    if (center?.length === 2) {
      const point = this.sketchFrame.toWorld(
        new Vector3(center[0], center[1], 0),
      );
      this.createPoint(point, previewScene);
    }
    if (positions.length === 1) {
      this.createPoint(positions[0], previewScene);
    } else {
      const line = new CSDashLine({
        vertexs: positions,
        lineWidth: curve?.curveStyle
          ? lineWidthOptions.dashed
          : lineWidthOptions.soild,
        dashed: !!curve?.curveStyle,
        ...dashOptions,
      });
      line.renderOrder = 999999;
      previewScene.add(line);
    }
  }
  createPoint(vertex, previewScene: Object3D) {
    const point = new CSPoint({
      vertex,
      pointType: 'endPoint',
    });
    point.hoverOn();
    point.setSize(6);
    point.renderOrder = 999999;
    previewScene.add(point);
  }
  // 判断是不是预览
  isExecuteTransaction() {
    return (
      this.selectedCurve &&
      (this.actionType === State.LINE || this.actionType === State.POINT)
    );
  }
  addConstraint(
    target: ICurve & { relative?: string[] },
    curve: ICurve,
    pickType: PickType,
  ) {
    if (
      (target?.type === 'Line' && curve?.type === 'Line') ||
      pickType === PickType.Null ||
      this.pickSnapInfo?.type === 'Bspline'
    ) {
      return;
    }
    const constraint =
      pickType == PickType.Point
        ? ConstraintType.Coincident
        : ConstraintType.PointOnObject;
    const curveId = curve?.id;
    const targetId = target?.id;
    const id_temp = curveId; // 约束的target id
    if (target.relative.includes(id_temp)) {
      return;
    }
    let flag = false;
    const constraints = target.constraints;
    // 查看是否已有约束
    for (const item of constraints) {
      if (item.type === constraint && item.target === id_temp) {
        flag = true;
        break;
      }
    }
    // 如果已有约束就返回
    if (flag) {
      return;
    }
    this.createConstraint(curveId, targetId, constraint);
  }
}

export const cmdDrag = () => {
  return CmdDrag.getInstance();
};
